<?php

/*
 * This script belongs to Aspect PHP.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * This script is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN-
 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details.
 */

/**
 * The default Aspect PHP pointcut implementation
 *
 * @package    aspectPhp
 * @subpackage lib
 * @author     gboisse
 */
class aspectPointcut extends aspectPointcutFilter {

    /** @var array Registered if the pointcut has arguments matching */
    protected $arguments;

    /**
     * Creates a new pointcut with the given arguments
     *
     * @param string $aspectClassName The name of the aspect class
     * @param string $adviceMethodName The name of the advice method
     * @param boolean $negate Used to negate the pointcut expression
     * @param string $pointcutPattern The pointcut pattern used to match the methods
     * @param array $arguments Used to match runtime evaluations
     */
    public function __construct($aspectClassName, $adviceMethodName, $negate = false, $pointcutPattern = '', $arguments = array()) {
        parent::__construct($aspectClassName, $adviceMethodName, $negate, $pointcutPattern);

        $this->arguments = $arguments;
    }

    /**
     * Checks if the specified $methodName from the given $className matches
     * with the requested $pointcut
     *
     * @param aspectJoinpoint $joinpoint The current joinpoint to match
     * @return boolean Returns true if the pointcut matches
     */
    public function matches(aspectJoinpoint $joinpoint) {

        $match = preg_match($this->pointcutPattern,
                        $joinpoint->getClassName() . '->' . $joinpoint->getMethodName());

        if (!$this->negate && $match || $this->negate && !$match) {
            if (empty($this->arguments)) {
                return true;
            }
            foreach ($this->arguments as $argument => $condition) {
                if (!$joinpoint->hasMethodArgument($argument)) {
                    return false;
                }
                $value = $joinpoint->getMethodArgument($argument);

                $result = eval(sprintf('return $value%s;', $condition));
                if (!$this->negate && !$result
                        || $this->negate && $result) {
                    return false;
                }
            }
            return true;
        }

        return false;
    }

}
